package cn.snmp.mutual.nms.mibs;

import java.awt.*;

import cn.snmp.mutual.uk.stack.AsnObject;

import java.net.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;

public class MibProfileLoader
{
    protected static int VERSION_A;
    protected static int VERSION_B;
    protected static int VERSION_C;
    protected int CURRENT_VERSION_A;
    protected int CURRENT_VERSION_B;
    protected int CURRENT_VERSION_C;
    protected String m_profile;
    protected ObjectInputStream m_inputStream;
    protected Vector m_elements;
    protected int m_nodeCount;
    
    public MibProfileLoader(final String profile) {
        this.CURRENT_VERSION_A = 1;
        this.CURRENT_VERSION_B = 2;
        this.CURRENT_VERSION_C = 0;
        this.m_profile = "";
        this.m_inputStream = null;
        this.m_elements = new Vector();
        this.m_nodeCount = 0;
        this.m_profile = profile;
    }
    
    public MibOperations load() {
        return this.buildMibOperations();
    }
    
    private void close() {
        try {
            if (this.m_inputStream != null) {
                this.m_inputStream.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            this.m_inputStream = null;
        }
    }
    
    public URL getURL(final String filename) {
        final Component component = new Component() {};
        final ClassLoader loader = component.getClass().getClassLoader();
        final URL url = loader.getResource(filename);
        if (AsnObject.debug > 6) {
            System.out.println("Cannot find resource [" + filename + "].");
        }
        return url;
    }
    
    public InputStream getInputStream(final URL url) {
        if (url != null) {
            final DocumentBuilderFactory documentbuilderfactory = DocumentBuilderFactory.newInstance();
            documentbuilderfactory.setNamespaceAware(true);
            documentbuilderfactory.setIgnoringComments(false);
            documentbuilderfactory.setIgnoringElementContentWhitespace(false);
            documentbuilderfactory.setCoalescing(true);
            try {
                final URLConnection urlconnection = url.openConnection();
                urlconnection.connect();
                final DocumentBuilder documentbuilder = documentbuilderfactory.newDocumentBuilder();
                if (AsnObject.debug > 6) {
                    System.out.println("Load rmp file [" + url + "].");
                }
                return urlconnection.getInputStream();
            }
            catch (Exception exception) {
                if (AsnObject.debug > 6) {
                    System.out.println("Fail to decode the file : " + url.toString() + " , the exception is : " + exception.toString());
                }
                return null;
            }
        }
        if (AsnObject.debug > 6) {
            System.out.println("Fail to decode the file : " + url.toString() + " the URL is null");
        }
        return null;
    }
    
    public ObjectInputStream getInputStream() {
        if (this.m_inputStream != null) {
            return this.m_inputStream;
        }
        try {
            final URL url = this.getURL(this.m_profile);
            InputStream is = null;
            if (url == null) {
                final File file = new File(this.m_profile);
                is = new FileInputStream(file);
            }
            else {
                is = this.getInputStream(url);
            }
            final BufferedInputStream bis = new BufferedInputStream(is);
            final ObjectInputStream stream = new ObjectInputStream(bis);
            return this.m_inputStream = stream;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public ObjectInputStream getInputStream_bak() {
        if (this.m_inputStream != null) {
            return this.m_inputStream;
        }
        try {
            final URL url = this.getURL(this.m_profile);
            final File file = new File(url.toString());
            final FileInputStream ifs = new FileInputStream(file);
            final BufferedInputStream bis = new BufferedInputStream(ifs);
            final ObjectInputStream stream = new ObjectInputStream(bis);
            return this.m_inputStream = stream;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private Hashtable readHashtable() {
        try {
            final ObjectInputStream stream = this.getInputStream();
            final Hashtable t = (Hashtable)stream.readObject();
            return t;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private Vector readVector() {
        try {
            final ObjectInputStream stream = this.getInputStream();
            final Vector t = (Vector)stream.readObject();
            return t;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private int readInt() {
        try {
            final ObjectInputStream stream = this.getInputStream();
            final int t = stream.readInt();
            return t;
        }
        catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
    
    public boolean loadMibNode(final MibModule module, final Vector nodes) {
        if (module.toString().equals("RAISECOM-PAE-MIB")) {
            System.err.println(module);
        }
        final Hashtable propreties = this.readHashtable();
        final MibNode node = new MibNode(module, propreties);
        if (AsnObject.debug > 6) {
            System.out.println("------> load MibNode [" + node.getLabel() + "]");
        }
        nodes.add(node);
        return true;
    }
    
    protected MibModule loadMibModule(final MibOperations operations) {
        final Hashtable propreties = this.readHashtable();
        final int count = this.readInt();
        this.m_nodeCount += count;
        final Vector elements = new Vector();
        final MibModule module = new MibModule(operations, propreties, elements);
        if (AsnObject.debug > 6) {
            System.out.println("---> load MibModule [" + module.toString() + "]");
        }
        for (int i = 0; i < count; ++i) {
            this.loadMibNode(module, elements);
        }
        if (this.CURRENT_VERSION_A > 1 || (this.CURRENT_VERSION_A == 1 && this.CURRENT_VERSION_B >= 5)) {
            final int iTrapCount = this.readInt();
            final Vector vTraps = new Vector();
            for (int j = 0; j < iTrapCount; ++j) {
                this.loadMibTrap(module, vTraps);
            }
            module.setMibTraps(vTraps);
            final int iTCCount = this.readInt();
            final Vector vTCs = new Vector();
            for (int k = 0; k < iTCCount; ++k) {
                this.loadMibTC(module, vTCs);
            }
            module.setMibTCs(vTCs);
        }
        if (AsnObject.debug > 6) {
            System.out.println("------> module [" + module.toString() + "] node size [" + count + "].");
        }
        return module;
    }
    
    public boolean loadMibTrap(final MibModule module, final Vector vTraps) {
        final Hashtable propreties = this.readHashtable();
        final MibTrap trap = new MibTrap(module, propreties);
        vTraps.add(trap);
        if (AsnObject.debug > 6) {
            System.out.println("------> load MibTrap [" + trap.getName() + "]");
        }
        return true;
    }
    
    public boolean loadMibTC(final MibModule module, final Vector vTCs) {
        final Hashtable propreties = this.readHashtable();
        final MibTC tc = new MibTC(propreties);
        vTCs.add(tc);
        if (AsnObject.debug > 6) {
            System.out.println("------> load MibTC [" + tc.getName() + "]");
        }
        return true;
    }
    
    protected MibOperations loadMibOperations() {
        try {
            final Hashtable copyright = this.readHashtable();
            final String version = (String)copyright.get("Version");
            final StringTokenizer tokenizer = new StringTokenizer(version, ".");
            final int count = tokenizer.countTokens();
            if (count != 3) {
                throw new Exception("bad rmp format");
            }
            final int a = Integer.parseInt(tokenizer.nextToken());
            final int b = Integer.parseInt(tokenizer.nextToken());
            final int c = Integer.parseInt(tokenizer.nextToken());
            if (MibProfileLoader.VERSION_A <= a && MibProfileLoader.VERSION_B <= b && MibProfileLoader.VERSION_C < c) {
                throw new Exception("Low Version");
            }
            this.CURRENT_VERSION_A = a;
            this.CURRENT_VERSION_B = b;
            this.CURRENT_VERSION_C = c;
            if (AsnObject.debug > 6) {
                System.out.println("------> MIB Profile Version " + version);
            }
            final Hashtable propreties = this.readHashtable();
            final Vector names = this.readVector();
            final Vector modules = new Vector();
            final MibOperations operations = new MibOperations(propreties, modules);
            for (int i = 0; i < names.size(); ++i) {
                modules.add(this.loadMibModule(operations));
            }
            return operations;
        }
        catch (Exception e) {
            if (AsnObject.debug > 6) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    public MibOperations buildMibOperations() {
        this.m_nodeCount = 0;
        MibOperations result = null;
        final long start = System.currentTimeMillis();
        try {
            result = this.loadMibOperations();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            this.close();
        }
        final long end = System.currentTimeMillis();
        if (AsnObject.debug > 6) {
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
            System.out.println("------> load MibNode count [" + this.m_nodeCount + "].");
            System.out.println("------> load mib profile use [" + (end - start) + "] ms");
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
            System.out.println("---------------------------------------------------------------");
        }
        return result;
    }
    
    static {
        MibProfileLoader.VERSION_A = 1;
        MibProfileLoader.VERSION_B = 2;
        MibProfileLoader.VERSION_C = 0;
    }
}
